package cn.iocoder.yudao.module.system.service.tenant;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.order.TenantOrderPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.order.TenantOrderSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.product.TenantProductSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenantrechargelog.vo.TenantRechargeLogSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.product.ProductDO;
import cn.iocoder.yudao.module.system.dal.dataobject.productsku.ProductSkuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantOrderDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantOrderReceiveDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantOrderUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantProductDO;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantAccountMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantOrderMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantOrderReceiveMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantOrderUserMapper;
import cn.iocoder.yudao.module.system.enums.order.OrderTypeEnum;
import cn.iocoder.yudao.module.system.enums.pay.TenantProductTypeEnum;
import cn.iocoder.yudao.module.system.enums.product.ProductDeliveryStatusEnum;
import cn.iocoder.yudao.module.system.enums.product.ProductDeliveryTypeEnum;
import cn.iocoder.yudao.module.system.enums.product.ProductEnum;
import cn.iocoder.yudao.module.system.mq.producer.product.ProductProducer;
import cn.iocoder.yudao.module.system.service.product.ProductService;
import cn.iocoder.yudao.module.system.service.productsku.ProductSkuService;
import cn.iocoder.yudao.module.system.service.tenantrechargelog.TenantRechargeLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ORDER_RECORD_ALREADY_PAID;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ORDER_RECORD_NOT_EXISTS;

@Service
@Validated
@Slf4j
public class TenantOrderServiceImpl implements TenantOrderService {


    @Resource
    private TenantOrderMapper tenantOrderMapper;

    @Resource
    private TenantOrderUserMapper tenantOrderUserMapper;

    @Resource
    private ProductService productService;

    @Resource
    private ProductSkuService productSkuService;

    @Resource
    private TenantService tenantService;

    @Resource
    private TenantProductService tenantProductService;

    @Resource
    private ProductProducer productProducer;

    @Resource
    private TenantOrderReceiveMapper tenantOrderReceiveMapper;

    @Resource
    private TenantRechargeLogService tenantRechargeLogService;


    @Override
    public void updateOrderPaid(PayOrderNotifyReqDTO notifyReqDTO) {

        // 验证订单
        TenantOrderDO orderDO = tenantOrderMapper.selectOne(TenantOrderDO::getOrderNo, notifyReqDTO.getMerchantOrderId());
        if (Objects.isNull(orderDO)) {
            throw exception(ORDER_RECORD_NOT_EXISTS);
        }
        if (PayOrderStatusEnum.isSuccess(orderDO.getPayStatus())) {
            throw exception(ORDER_RECORD_ALREADY_PAID);
        }
        orderDO.setPayOrderId(notifyReqDTO.getPayOrderId())
                .setPayStatus(PayOrderStatusEnum.SUCCESS.getStatus())
                .setPayTime(LocalDateTime.now());
        if (ProductDeliveryTypeEnum.isSystem(orderDO.getDeliveryType())) {
            orderDO.setDeliveryStatus(ProductDeliveryStatusEnum.DELIVERY.getStatus());
        }
        tenantOrderMapper.updateById(orderDO);
        // 更新租户账户信息 ----
        TenantRechargeLogSaveReqVO saveReqVO = new TenantRechargeLogSaveReqVO();
        saveReqVO.setTenantId(orderDO.getTenantId());
        saveReqVO.setAmount(orderDO.getPayPrice());
        saveReqVO.setPayType(2);
        saveReqVO.setRemark("在线支付订单："+orderDO.getOrderNo());
        tenantRechargeLogService.createTenantRechargeLog(saveReqVO);

        TenantUtils.execute(orderDO.getTenantId(), () -> {

            ProductDO product = productService.getProductByCode(orderDO.getBizType());

            if (Objects.equals(product.getCode(), ProductEnum.WALLET.getCode())) {
                // 钱包充值
                tenantService.updateWallet(orderDO.getTenantId(), orderDO.getTotalPrice().doubleValue(), true);
            } else {
                // 购买的话， 一般是购买数量上限， 用于扩容
                if (OrderTypeEnum.isBuy(orderDO.getOrderType())) {
                    handleBuyBiz(product, orderDO);
                }
                // 续费的话， 一般都是基于已有的数据id 去延长 可用时间
                else if (OrderTypeEnum.isRenewal(orderDO.getOrderType())) {
                    handleRenewalBiz(product, orderDO);
                }
                // 更新产品售出数量
                productService.updateProductSaleCount(orderDO.getNum(), product.getId());
            }
        });
    }

    private void handleRenewalBiz(ProductDO product, TenantOrderDO orderDO) {

        // 外呼坐席
//        if (Objects.equals(orderDO.getBizType(), ProductEnum.CALL_AGENT.getCode())) {
        // 说明一下： order里面的 num 为续费时长，因为没有走sku，所以获取不到 expireTime;
        productProducer.sendProductMessage(product.getCode(), 1, orderDO.getNum(), orderDO.getTenantId(), orderDO.getBizId());
//        }

    }


    private void handleBuyBiz(ProductDO product, TenantOrderDO orderDO) {
        ProductSkuDO productSku = productSkuService.getProductSku(orderDO.getBizId());
        List<Long> keyList;
        boolean isUserType = product.getType() == 1;
        // 是在这里判断是否为员工套餐 或 企业套餐， 这里暂时的设定是员工套餐是话费级别的，发送到个人账户的。
        if (isUserType) {
            List<TenantOrderUserDO> orderUserDOList = tenantOrderUserMapper.selectList(TenantOrderUserDO::getOrderId, orderDO.getId());
            keyList = orderUserDOList.stream().map(TenantOrderUserDO::getOwnerUserId).collect(Collectors.toList());
        } else {
            keyList = Collections.singletonList(orderDO.getTenantId());
        }

        keyList.forEach(keyId -> {

            @Valid TenantProductSaveReqVO productSaveReqVO = new TenantProductSaveReqVO();
            productSaveReqVO.setTotalNum(orderDO.getNum());
            productSaveReqVO.setRemainNum(orderDO.getNum());
            productSaveReqVO.setExpireTime(productSku.getExpireTime());
            productSaveReqVO.setType(product.getType());
            productSaveReqVO.setProductCode(product.getCode());
            productSaveReqVO.setProductName(product.getName());
            if (productSku.getExpireTime() != 0) {
                productSaveReqVO.setExpireAt(LocalDateTimeUtil.now().plusDays(productSku.getExpireTime()));
            }
            if (isUserType) {
                productSaveReqVO.setOwnerUserId(keyId);
            } else {
                productSaveReqVO.setOwnerUserId(orderDO.getOwnerUserId());
            }
            Long bizId = tenantProductService.createTenantProduct(productSaveReqVO);
            String code = product.getCode() + ":" + keyId;

            tenantService.putTenantProductHashMap(code, bizId, productSaveReqVO.getRemainNum());
            // 一般的套餐后续执行 付费后的异步响应，执行坐席/客服/等等账号的创建
            productProducer.sendProductMessage(product.getCode(), orderDO.getNum(), productSku.getExpireTime(), orderDO.getTenantId(), null);

            // 在这里写外呼channel的更新： 根据code->分别对照phoneMode -> 获取对应的channelId列表
            tenantService.updateTenantCallChannel(orderDO.getTenantId(), product.getCode());
        });
    }


    @Override
    public Long createTenantOrder(TenantOrderSaveReqVO createReqVO) {
        // 插入
        TenantOrderDO tenantOrder = BeanUtils.toBean(createReqVO, TenantOrderDO.class);
        tenantOrderMapper.insert(tenantOrder);
        // 返回
        return tenantOrder.getId();
    }

    @Override
    public void updateTenantOrder(TenantOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateTenantOrderExists(updateReqVO.getId());
        // 更新
        TenantOrderDO updateObj = BeanUtils.toBean(updateReqVO, TenantOrderDO.class);
        tenantOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteTenantOrder(Long id) {
        // 校验存在
        validateTenantOrderExists(id);
        // 删除
        tenantOrderMapper.deleteById(id);
    }

    private void validateTenantOrderExists(Long id) {
        if (tenantOrderMapper.selectById(id) == null) {
            throw exception(new ErrorCode(100_300_303, "订单不存在"));
        }
    }

    @Override
    public TenantOrderDO getTenantOrder(Long id) {
        return tenantOrderMapper.selectById(id);
    }

    @Override
    public PageResult<TenantOrderDO> getTenantOrderPage(TenantOrderPageReqVO pageReqVO) {
        return tenantOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public TenantOrderReceiveDO getOrderReceiver(Long orderId) {
        return tenantOrderReceiveMapper.selectOne(TenantOrderReceiveDO::getOrderId, orderId);
    }
}
